<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2021/2/24
 * Time: 16:16
 */
declare(strict_types=1);

namespace App\Service;
use App\Model\Dao\MchAccountAccessDao;
use App\Model\Dao\MchAccountAccessDetailDao;
use App\Model\Dao\MchAccountDao;
use App\Model\Dao\RateSettleDao;
use App\Model\Dao\RateSettleDisDao;
use App\Model\Dao\TradeOrderDetailDao;
use App\Model\Dao\TradeOrderDisDao;
use App\Utils\CustomUtils;
use App\Utils\RedisUtils;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Exception;

/**
 * Class SettleTradeOrderDisFeeService
 * @package App\Service
 * 交易订单拒付结算
 */
class SettleTradeOrderDisFeeService extends CommonService
{

    /**
     * @Inject()
     * @var TradeOrderDetailDao
     */
    private $TradeOrderDetailDao;

    /**
     * @Inject()
     * @var TradeOrderDisDao
     */
    private $TradeOrderDisDao;

    /**
     * @Inject()
     * @var MchAccountDao
     */
    private $MchAccountDao;

    /**
     * @Inject()
     * @var MchAccountAccessDao
     */
    private $MchAccountAccessDao;

    /**
     * @Inject()
     * @var MchAccountAccessDetailDao
     */
    private $MchAccountAccessDetailDao;

    /**
     * @Inject()
     * @var RateSettleDao
     */
    private $RateSettleDao;

    /**
     * @Inject()
     * @var RateSettleDisDao
     */
    private $RateSettleDisDao;

    public function statAndPush($statStartTime, $statEndTime) {
        // 查出所有商户
        $mchIds = $this->TradeOrderDisDao->getDistinctMchIds($statStartTime, $statEndTime);
        foreach ($mchIds as $value) {
            $ids = $this->TradeOrderDisDao->getNeedDisIds($value['mchId'], $statStartTime, $statEndTime);
            $disCount = count($ids);
            $transSuccessCount = $this->TradeOrderDetailDao->getTransSuccessByRangeTime($value['mchId'], $statStartTime, $statEndTime);

            CustomUtils::xzxDebug("商户{$value['mchId']}交易成功数：{$transSuccessCount}，拒付数：{$disCount}");
            if ($disCount == 0) {
                continue;
            }

            $rate = $this->RateSettleDao->getByMchId($value['mchId']);
            CustomUtils::xzxDebug($rate);
            $rateDis = $this->RateSettleDisDao->get($rate['disFeeId']);
            CustomUtils::xzxDebug($rateDis);
            $content = json_decode($rateDis['content'], true);
            // CustomUtils::xzxDebug($content);
            // CustomUtils::xzxDebug($disCount);
            // CustomUtils::xzxDebug($transSuccessCount);
            // CustomUtils::xzxDebug(intval(($disCount / $transSuccessCount) * 100));

            $disFee = 0;
            foreach ($content as $c) {
                // CustomUtils::xzxDebug($c['count']);
                // CustomUtils::xzxDebug($c['rate']);
                // CustomUtils::xzxDebug($c['disFee']);
                if ($disCount >= $c['count'] && intval(($disCount / $transSuccessCount) * 10000) >= $c['rate']) {
                    if($disFee < $c['disFee']) {
                        $disFee = $c['disFee'];
                    }                    
                }
            }
            if ($disFee == 0) {
                CustomUtils::xzxDebug("商户{$value['mchId']}拒付费用没有匹配或者为0，无需进行拒付费用结算");
                continue;
            }

            if (count($ids) > 0) {
                foreach ($ids as $v) {
                    $data = [
                        "accessType"    => ACCESS_TYPE_DIS_FEE,
                        "disId"         => $v["id"],
                        "mchAccountId"  => $v["mchAccountId"],
                        "amount"        => $disFee
                    ];
                    RedisUtils::redisResource()->rPush("MchAccountAccessList", serialize($data));
                }
            }

            CustomUtils::xzxDebug("商户{$value['mchId']}拒付费用条数" , count($ids));
        }
    }

    public function handle($param) {
        // 校验
        $tradeOrderDis = $this->TradeOrderDisDao->get($param['disId']);
        if(!$tradeOrderDis) {
            throw new Exception('拒付单不存在，终止处理', FAILED_CODE);
        }
        if($tradeOrderDis['disFeeSettleStatus'] == 1) {
            throw new Exception('订单已经拒付费用结算', FAILED_CODE);
        }
        $isAccess = $this->MchAccountAccessDao->getWhere(['disId' => $param['disId'], 'accessType' => ACCESS_TYPE_DIS_FEE]);
        if ($isAccess) {
            throw new Exception('拒付单已进行拒付费用结算', FAILED_CODE);
        }
        $mchAccount = $this->MchAccountDao->get($param['mchAccountId']);
        if(!$mchAccount) {
            throw new Exception('查询账户记录失败', FAILED_CODE);
        }

        // 乐观锁版本号+1
        $updateVersion = $mchAccount['updateVersion'] + 1;

        // 结算金额 余额前后
        $disFee = $param['amount'];
        $beforeTradeCashAmount = $mchAccount['tradeCashAmount'];
        $afterTradeCashAmount = $mchAccount['tradeCashAmount'] - $disFee;

        // 开启事务
        Db::beginTransaction();
        try {
            // step
            // 1.拒付金额出账可提现账户
            // 2.更新拒付单状态
            // 3.更新订单状态
            // 4.更新账户余额

            // step 1
            $this->handleOutDisFee($param, $tradeOrderDis, $mchAccount, $disFee, $beforeTradeCashAmount, $afterTradeCashAmount);

            // step 2
            $updateTradeOrderDis = array(
                'disFeeSettleStatus' => 1,
                'disFeeSettleTime'   => time()
            );
            $this->TradeOrderDisDao->update($param['disId'], $updateTradeOrderDis);

            // step 3
            $updateTradeOrder = array(
                'disFee' => $disFee
            );
            $this->TradeOrderDetailDao->update($tradeOrderDis['orderId'], $updateTradeOrder);

            // step 4
            $updateMchAccount = array(
                "tradeCashAmount"   => $afterTradeCashAmount,
                "updateVersion"     => $updateVersion
            );
            $result = $this->MchAccountDao->updateWhere([
                "id" => $param['mchAccountId'],
                "updateVersion" => $mchAccount['updateVersion']
            ], $updateMchAccount);

            // 如果更新账户失败，重试，最多3次
            if (!$result) {
                throw new \Exception("更新账户失败");
            }

        } catch (\Throwable $e) {
            CustomUtils::xzxDebug($e->getMessage());
            Db::rollBack();

            // 失败重试，最多3次
            $this->tryOneMore($param);

            return CustomUtils::xeServiceReturnData(FAILED_CODE, "交易拒付处理费结算失败");
        }
        Db::commit();

        return CustomUtils::xeServiceReturnData(SUCCESS_CODE, "交易拒付处理费结算成功");

    }

    /**
     * @param $param
     * @param $tradeOrderDis
     * @param $mchAccount
     * @param $amount
     * @param $beforeAmount
     * @param $afterAmount
     * 交易可提现账户拒付处理费出账
     */
    private function handleOutDisFee($param, $tradeOrderDis, $mchAccount, $amount, $beforeAmount, $afterAmount) {

        // 写主表
        $mchAccountAccess = array(
            "id"           => CustomUtils::createUUID(),
            "mchId"        => $tradeOrderDis["mchId"],
            "mchNo"        => $tradeOrderDis["mchNo"],
            "mchAccountId" => $param['mchAccountId'],
            "accessType"   => ACCESS_TYPE_DIS_FEE,
            "accountType"  => ACCOUNT_TYPE_CASH,
            "orderId"      => $tradeOrderDis['id'],
            "tradeNo"      => $tradeOrderDis['tradeNo'],
            "amount"       => -$amount,
            "currency"     => $tradeOrderDis['transCurrency'],
            "status"       => 1,
            "remark"       => "拒付订单拒付处理费出账",
            "createTime"   => CustomUtils::xzxGetMsecTime()
        );
        $this->MchAccountAccessDao->add($mchAccountAccess);

        // 写明细表
        $mchAccountAccessDetail = array(
            "id"                => CustomUtils::createUUID(),
            "mchId"             => $tradeOrderDis["mchId"],
            "mchNo"             => $tradeOrderDis["mchNo"],
            "mchAccountId"      => $param['mchAccountId'],
            "accessId"          => $mchAccountAccess['id'],
            "accountType"       => ACCOUNT_TYPE_CASH,
            "inOutType"         => DETAIL_TYPE_OUT,
            "type"              => TYPE_DIS_FEE_OUT,
            "beforeTotalAmount" => $beforeAmount,
            "afterTotalAmount"  => $afterAmount,
            "amount"            => -$amount,
            "orderId"           => $tradeOrderDis['id'],
            "tradeNo"           => $tradeOrderDis['tradeNo'],
            "currency"          => $tradeOrderDis['transCurrency'],
            "remark"            => "拒付订单拒付处理费出账",
            "createTime"        => CustomUtils::xzxGetMsecTime()
        );
        $this->MchAccountAccessDetailDao->add($mchAccountAccessDetail);
    }

}